package com.neusoft.neuiotms.dcom.service.impl;

import java.util.List;

import javax.persistence.EntityNotFoundException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.eventbus.AsyncEventBus;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcom.converter.MaintainPlanConverter;
import com.neusoft.neuiotms.dcom.dto.MaintainPlanDTO;
import com.neusoft.neuiotms.dcom.model.MaintainPlan;
import com.neusoft.neuiotms.dcom.model.enums.MaintainPlanStatus;
import com.neusoft.neuiotms.dcom.repository.MaintainPlanRepository;
import com.neusoft.neuiotms.dcom.repository.MaintainTaskRepository;
import com.neusoft.neuiotms.dcom.service.MaintainPlanService;
import com.neusoft.neuiotms.dcom.task.maintain.event.MaintainPlanDeleteEvent;
import com.neusoft.neuiotms.dcom.task.maintain.event.MaintainPlanUpdateEvent;

@Service
public class MaintainPlanServiceImpl implements MaintainPlanService {

    @Autowired
    private MaintainPlanRepository maintainPlanRepository;

    @Autowired
    private MaintainTaskRepository maintainTaskRepository;

    @Autowired
    private MaintainPlanConverter maintainPlanConventer;

    @javax.annotation.Resource(name = "modelUpdateEventBus")
    private AsyncEventBus modelUpdateEventBus;

    @Override
    public List<MaintainPlanDTO> findAll() {
        final List<MaintainPlan> entity = this.maintainPlanRepository.findAll();
        final List<MaintainPlanDTO> dtos =
                this.maintainPlanConventer.toListDTO(entity);
        return dtos;
    }

    @Override
    public Page<MaintainPlanDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<MaintainPlan> models = this.maintainPlanRepository.search(pageable, searchable);
        return this.maintainPlanConventer.toPageDTO(models);
    }

    @Override
    @Transactional
    public MaintainPlanDTO create(final MaintainPlanDTO dto) {
        //        final MaintainPlan checkName = this.maintainPlanRepository.findByName(dto.getName());
        //        if (checkName != null) {
        //            throw new UnitedException(ExceptionConstants.NAME_CAN_NOT_DUPLICATE, new Object[] {});
        //        }

        final MaintainPlan model = this.maintainPlanConventer.toModel(dto);

        this.maintainPlanRepository.save(model);

        if (model.getStatus().name().equals(MaintainPlanStatus.enable.name())) {
            this.postStatusUpdateEvent(model);
        }

        return this.maintainPlanConventer.toDTO(model);
    }

    @Override
    @Transactional
    public MaintainPlanDTO update(final Long id, final MaintainPlanDTO dto) {
        MaintainPlan model;
        try {
            model = this.maintainPlanRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        if (!dto.getStatus().name().equals(model.getStatus().name())
                && model.getStatus().name().equals(MaintainPlanStatus.enable.name())) {
            this.postStatusUpdateEvent(model);
        }

        if (!dto.getStatus().name().equals(model.getStatus().name())
                && model.getStatus().name().equals(MaintainPlanStatus.disable.name())) {
            this.postStatusDeleteEvent(model);
        }

        if (model != null) {
            dto.setId(model.getId());
        }

        // 修改计划时，如果计划生成过任务，创建新计划版本，即复制，版本号在原计划的基础上加1，原计划停用
        final Searchable searchable = new Searchable();
        searchable.put("planId", id);
        final Long count = this.maintainTaskRepository.getCount(searchable);

        if (count > 0) {
            // 废弃原来的计划
            model.setDeleteFlag(true);
            this.maintainPlanRepository.save(model);

            // 创建新计划
            dto.setId(null);
            dto.setVersion(dto.getVersion() + 1);
            final MaintainPlan newModel = this.maintainPlanConventer.toModel(dto);
            this.maintainPlanRepository.save(newModel);

            return this.maintainPlanConventer.toDTO(newModel);
        }

        model = this.maintainPlanConventer.toModel(dto);
        this.maintainPlanRepository.save(model);
        return this.maintainPlanConventer.toDTO(model);
    }

    @Override
    public MaintainPlanDTO details(final Long id) {
        final MaintainPlan model;
        try {
            model = this.maintainPlanRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        return this.maintainPlanConventer.toDTO(model, false);
    }

    @Override
    public void delete(final Long id) {
        final Searchable searchable = new Searchable();
        searchable.put("planId", id);
        final Long count = this.maintainTaskRepository.getCount(searchable);

        if (count > 0) {
            throw new UnitedException(ExceptionConstants.FOREIGN_KEY_CONSTRAINT_TASK, new Object[] {id });
        }
        this.maintainPlanRepository.deleteById(id);
    }

    @Override
    @Transactional
    public MaintainPlanDTO changeStatus(final Long id, final String flag) {
        MaintainPlan model;
        try {
            model = this.maintainPlanRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        if (model != null) {
            model.setStatus(MaintainPlanStatus.valueOf(flag));
        }

        this.maintainPlanRepository.save(model);

        if (model.getStatus().name().equals(MaintainPlanStatus.enable.name())) {
            this.postStatusUpdateEvent(model);
        }

        if (model.getStatus().name().equals(MaintainPlanStatus.disable.name())) {
            this.postStatusDeleteEvent(model);
        }

        return this.maintainPlanConventer.toDTO(model);
    }

    @Override
    public List<MaintainPlanDTO> findAllEnabled() {
        final List<MaintainPlan> entity = this.maintainPlanRepository.findByStatus(MaintainPlanStatus.enable);
        final List<MaintainPlanDTO> dtos =
                this.maintainPlanConventer.toListDTO(entity);
        return dtos;
    }

    /**
     * 启用时，发送状态变更事件
     */
    private void postStatusUpdateEvent(final MaintainPlan maintainPlan) {

        final MaintainPlanUpdateEvent event = new MaintainPlanUpdateEvent();
        event.setName(maintainPlan.getCode());
        event.setGroup(maintainPlan.getName());
        event.setStatus(true);
        event.setPlanId(maintainPlan.getId());
        event.setPeriod(maintainPlan.getPeriod());
        this.modelUpdateEventBus.post(event);
    }

    /**
     * 停用/删除时，发送状态变更事件
     */
    private void postStatusDeleteEvent(final MaintainPlan maintainPlan) {
        final MaintainPlanDeleteEvent event = new MaintainPlanDeleteEvent();
        event.setName(maintainPlan.getCode());
        event.setGroup(maintainPlan.getName());
        event.setStatus(false);
        event.setPlanId(maintainPlan.getId());
        event.setPeriod(maintainPlan.getPeriod());
        this.modelUpdateEventBus.post(event);
    }

}
